// Producer Consumer Problem
// ml:ldf += -pthread
// ml:run = $bin < input
#include <iostream>
#include <condition_variable>
#include <array>
#include <thread>
#include <vector>
#include <string>
#include <atomic>
#include <mutex>
#include <unistd.h>
#include <semaphore.h>
#include <err.h>

// exceptions
struct canceled {};

namespace v1
{
    struct semaphore
    {
        void alloc()
        {
            std::unique_lock<std::mutex> _{m};
            cv.wait(_, [this] { return counter > 0; });
            counter--;
        }

        void free()
        {
            std::unique_lock<std::mutex> _{m};
            ++counter;
            cv.notify_one();
        }

    private:
        int counter{};
        std::condition_variable cv;
        std::mutex m;
    };
}

namespace v2
{
    struct semaphore
    {
        semaphore()
        {
            if (sem_init(&sem, false, 0) < 0)
                err(1, "sem init");
        }

        void alloc()
        {
            if (sem_wait(&sem) < 0)
                err(1, "alloc");
        }

        void free()
        {
            if (sem_post(&sem) < 0)
                err(1, "free");
        }

    private:
        ::sem_t sem;
    };
}

using v1::semaphore;

template <class T>
struct channel
{
    channel()
    {
        rw.free();
        m.free();
    }

    void write(T id)
    {
        auto s = std::to_string(id);
        auto out{"\e[34mwriter\e[0m thread " + s + " \e[33msend the writing require\e[0m\n"};
        ::write(1, out.data(), out.size());

        rw.alloc();

        out = "\e[34mwriter\e[0m thread " + s + " \e[32mis writing!\e[0m\n";
        ::write(1, out.data(), out.size());

        out = "\e[34mwriter\e[0m thread " + s + " \e[31mend writing!\e[0m\n";
        ::write(1, out.data(), out.size());

        rw.free();
    }

    void read(T id)
    {
        auto s = std::to_string(id);
        std::string out{"\e[35mreader\e[0m thread " + s + " \e[33msend the reading require\e[0m\n"};
        ::write(1, out.data(), out.size());
        m.alloc();
        if (living_reader == 0) rw.alloc();
        living_reader++;
        m.free();

        out = "\e[35mreader\e[0m thread " + s + " \e[32mis reading!\e[0m\n";
        ::write(1, out.data(), out.size());

        out = "\e[35mreader\e[0m thread " + s + " \e[31mend read!\e[0m\n";
        ::write(1, out.data(), out.size());

        m.alloc();
        living_reader--;

        if (living_reader == 0) rw.free();

        m.free();
    }

private:
    semaphore rw;
    semaphore m;
    std::atomic<int> living_reader{};
};

int main()
{
    std::vector<std::thread> threads;
    std::mutex m_output;
    channel<int> chn;
    std::string type;
    int id;
    while (std::cin >> id >> type) {
        if (type.size() != 1) return 1;
        switch (type[0]) {
            case 'R':
                threads.emplace_back([&chn, id] () mutable {
                    chn.read(id);
                });
                break;
            case 'W':
                threads.emplace_back([&chn, id] {
                    chn.write(id);
                });
                break;
            default: return 2;
        }
    }

    for (auto& thread: threads)
        if (thread.joinable())
            thread.join();
}

